package rs.udd.service.util;

import org.springframework.security.authentication.AnonymousAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;

import rs.udd.exceptions.UserAuthenticationCheckException;
import rs.udd.exceptions.password.NewPasswordMismatchException;
import rs.udd.exceptions.password.PasswordMismatchException;
import rs.udd.model.AbstractUser;
import rs.udd.model.Admin;
import rs.udd.model.Advertiser;
import rs.udd.model.Agent;
import rs.udd.service.dto.user.UserPasswordEditDto;

public class SecurityUtil {

	public static final String ADMIN_ROLE_ONLY = "hasRole('ADMIN')";
	public static final String AGENT_ROLE_ONLY = "hasRole('AGENT')";
	public static final String ADVERTISER_ROLE_ONLY = "hasRole('ADVERTISER')";

	public static final String AGENT_OR_ADMIN_ROLE = "hasRole('AGENT') or hasRole('ADMIN')";
	public static final String ADVERTISER_OR_ADMIN_ROLE = "hasRole('ADVERTISER') or hasRole('ADMIN')";

	// this private constructor prevents this class from instantiation
	private SecurityUtil() {
	}

	public static <E extends AbstractUser> void checkPasswordChange(UserPasswordEditDto dto) throws PasswordMismatchException {
		String newUserProvidedRawPassword = dto.getNewPassword();
		String newUserProvidedRepeatedRawPassword = dto.getNewPasswordRepeated();

		if (!newUserProvidedRawPassword.equals(newUserProvidedRepeatedRawPassword)) {
			throw new NewPasswordMismatchException("New password missmatch");
		}
	}

	public static <E extends AbstractUser> void checkLoggedUser(E checkingUser) throws UserAuthenticationCheckException {

		@SuppressWarnings("unchecked")	// only users that extend AbstractUser.class can be stored in session
		E loggedUser = (E) SecurityContextHolder.getContext().getAuthentication().getPrincipal();

		boolean compare = loggedUser.getId() == checkingUser.getId();
		if (!compare) {
			String message = "User from session with id '" + loggedUser.getId()
					+ "' is not equal to checking user with id '" + checkingUser.getId() + "'";
			throw new UserAuthenticationCheckException(message);
		}
	}
	
	@SuppressWarnings("unchecked")	// only users that extend AbstractUser.class can be stored in session
	public static <T extends AbstractUser> T getLoggedUser(Class<T> userClazz) {
		return (T) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
	}

	public static <T extends AbstractUser> boolean checkLoggedRole(Class<T> userClazz) {
		UserDetails loggedUser = null;
		Authentication auth = SecurityContextHolder.getContext().getAuthentication();

		if (auth instanceof AnonymousAuthenticationToken) { //anonymous
			return false;
		} else {
			loggedUser = (UserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
		}

		if (loggedUser instanceof Agent) {
			Agent agent = (Agent) loggedUser;
			return agent.getClass() == userClazz;
		} else if (loggedUser instanceof Advertiser) {
			Advertiser advertiser = (Advertiser) loggedUser;
			return advertiser.getClass() == userClazz;
		} else if (loggedUser instanceof Admin) { // admin
			Admin admin = (Admin) loggedUser;
			return admin.getClass() == userClazz;
		}
		
		return false;
	}

}
